package postgres

import (
	"context"
	"errors"
	"github.com/jackc/pgx/v5"
	"log"
	"ozonTest/internal/domain/comments/model"
	"sync"
)

type commentsDAO struct {
	conn *pgx.Conn
	m    sync.RWMutex
}

func NewCommentsRepo(conn *pgx.Conn) *commentsDAO {
	return &commentsDAO{conn: conn}
}

func (c *commentsDAO) CreateComment(comment *model.Comment) error {
	// Check if comments are enabled for the post
	var commentsEnabled bool
	query := `SELECT comments_enabled FROM posts WHERE id = $1`
	err := c.conn.QueryRow(context.Background(), query, comment.PostID).Scan(&commentsEnabled)
	if err != nil {
		log.Printf("Error checking comments enabled: %v", err)
		return err
	}

	if !commentsEnabled {
		err := errors.New("comments are disabled for this post")
		log.Printf("Error creating comment: %v", err)
		return err
	}

	// Insert the comment
	query = `INSERT INTO comments (post_id, parent_id, content) VALUES ($1, $2, $3) RETURNING id, created_at`
	err = c.conn.QueryRow(context.Background(), query, comment.PostID, comment.ParentID, comment.Content).Scan(&comment.ID, &comment.CreatedAt)
	if err != nil {
		log.Printf("Error creating comment: %v", err)
		return err
	}

	log.Printf("Comment created: %+v", comment)
	return nil
}

func (c *commentsDAO) CreateReply(parentID int, reply *model.Comment) error {
	query := `INSERT INTO comments (post_id, parent_id, content) VALUES ($1, $2, $3) RETURNING id, created_at`
	err := c.conn.QueryRow(context.Background(), query, reply.PostID, parentID, reply.Content).Scan(&reply.ID, &reply.CreatedAt)
	if err != nil {
		log.Printf("Error creating reply: %v", err)
		return err
	}

	log.Printf("Reply created: %+v", reply)
	return nil
}

func (c *commentsDAO) GetComment(id int) (*model.Comment, error) {
	comment := &model.Comment{}
	query := `SELECT id, post_id, parent_id, content, created_at FROM comments WHERE id = $1`
	err := c.conn.QueryRow(context.Background(), query, id).Scan(&comment.ID, &comment.PostID, &comment.ParentID, &comment.Content, &comment.CreatedAt)
	if err != nil {
		if errors.Is(err, pgx.ErrNoRows) {
			log.Printf("Comment not found: ID %d", id)
			return nil, errors.New("comment not found")
		}
		log.Printf("Error retrieving comment: %v", err)
		return nil, err
	}

	log.Printf("Comment retrieved: %+v", comment)
	return comment, nil
}

func (p *commentsDAO) GetAllComments() ([]model.Comment, error) {
	var comments []model.Comment
	query := `SELECT id, post_id, parent_id, content, created_at FROM comments ORDER BY created_at DESC`
	rows, err := p.conn.Query(context.Background(), query)
	if err != nil {
		log.Printf("Error getting all posts: %v", err)
		return nil, err
	}
	defer rows.Close()
	for rows.Next() {
		var comment model.Comment
		err := rows.Scan(&comment.ID, &comment.PostID, &comment.ParentID, &comment.Content, &comment.CreatedAt)
		if err != nil {
			log.Printf("Error scanning row: %v", err)
			return nil, err
		}
		comments = append(comments, comment)
	}
	log.Printf("All posts retrieved: %+v", comments)
	return comments, nil
}

func (c *commentsDAO) DeleteComment(id int) error {
	query := `DELETE FROM comments WHERE id = $1`
	commandTag, err := c.conn.Exec(context.Background(), query, id)
	if err != nil {
		log.Printf("Error deleting comment: %v", err)
		return err
	}

	if commandTag.RowsAffected() == 0 {
		err := errors.New("comment not found")
		log.Printf("Comment not found for deletion: ID %d", id)
		return err
	}

	log.Printf("Comment deleted: ID %d", id)
	return nil
}

func (c *commentsDAO) GetCommentsByPost(postID int) ([]*model.Comment, error) {
	query := `WITH RECURSIVE comment_tree AS (
        SELECT id, post_id, parent_id, content, created_at
        FROM comments
        WHERE post_id = $1 AND parent_id IS NULL

        UNION ALL

        SELECT c.id, c.post_id, c.parent_id, c.content, c.created_at
        FROM comments c
        INNER JOIN comment_tree ct ON c.parent_id = ct.id
    )
    SELECT id, post_id, parent_id, content, created_at FROM comment_tree ORDER BY created_at DESC`
	rows, err := c.conn.Query(context.Background(), query, postID)
	if err != nil {
		log.Printf("Error retrieving comments by post: %v", err)
		return nil, err
	}
	defer rows.Close()

	commentMap := make(map[int]*model.Comment)
	var rootComments []*model.Comment

	for rows.Next() {
		comment := &model.Comment{}
		err := rows.Scan(&comment.ID, &comment.PostID, &comment.ParentID, &comment.Content, &comment.CreatedAt)
		if err != nil {
			log.Printf("Error scanning comment row: %v", err)
			return nil, err
		}

		comment.Replies = []*model.Comment{}
		commentMap[comment.ID] = comment

		if comment.ParentID == nil {
			rootComments = append(rootComments, comment)
		}
	}

	if err := rows.Err(); err != nil {
		log.Printf("Error iterating over comment rows: %v", err)
		return nil, err
	}

	for _, comment := range commentMap {
		if comment.ParentID != nil {
			parentComment, ok := commentMap[*comment.ParentID]
			if ok {
				parentComment.Replies = append(parentComment.Replies, comment)
			}
		}
	}

	log.Printf("Comments retrieved for PostID %d: %+v", postID, rootComments)
	return rootComments, nil
}
